package com.spzx.cart.service.impl;

import com.spzx.cart.api.domain.CartInfo;
import com.spzx.cart.service.ICartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.vo.ProductSkuVo;
import com.spzx.product.api.vo.SkuPriceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author XC
 * @version 1.0
 * @description
 * @knowledge
 */
@Service
public class CartServiceImpl implements ICartService {
    @Autowired
    private RemoteProductService remoteProductService;
    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        // 判断商品是否在购物车中存在，若存在，则更新数量，若不存在，则远程获取商品信息并加入到购物车中
        // 获取当前登录用户的id
        Long userId = SecurityUtils.getUserId();
        // 获取当前登录用户的购物车key
        String cartKey = getCartKey(userId);

        /*
        HashOperations hashOperations = redisTemplate.opsForHash();
        // redis的 key，hash的 key
        CartInfo cartInfo = (CartInfo)hashOperations.get(cartKey, skuId.toString());
        */
        // 先指定 redis的 key，再指定 hash的 key，不会出现上面混用的情况
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        // CartInfo cartInfo = boundHashOperations.get(skuId.toString());
        String hashKey = skuId.toString();

        if (boundHashOperations.hasKey(hashKey)) {
            // 若存在，则更新数量，上限 10
            CartInfo cartInfo = boundHashOperations.get(hashKey);
            int totalNum = cartInfo.getSkuNum() + skuNum;
            cartInfo.setSkuNum(Math.min(totalNum, 10));
            boundHashOperations.put(hashKey, cartInfo);

        } else {
            // 判断购物车商品种类，若数量大于等于 3种则不再增加新的商品
            Long skuCount = boundHashOperations.size();
            if (++skuCount > 3) {
                throw new RuntimeException("购物车商品种类不能超过 3种");
            }

            // 若不存在，则远程获取商品信息并加入到购物车中
            R<ProductSkuVo> productSkuResult = remoteProductService.getProductSku(skuId, SecurityConstants.INNER);

            if (productSkuResult.getCode() == R.FAIL) {
                throw new RuntimeException("远程调用失败：" + productSkuResult.getMsg());
            }

            ProductSkuVo productSkuVo = productSkuResult.getData();

            // 组装 cartInfo
            CartInfo cartInfo = new CartInfo();
            cartInfo.setSkuId(skuId);
            cartInfo.setSkuName(productSkuVo.getSkuName());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setSkuPrice(productSkuVo.getSalePrice());
            cartInfo.setCartPrice(productSkuVo.getSalePrice());
            cartInfo.setThumbImg(productSkuVo.getThumbImg());
            cartInfo.setIsChecked(1);
            cartInfo.setUserId(userId);
            cartInfo.setCreateTime(new Date());
            boundHashOperations.put(hashKey, cartInfo);

        }
    }

    @Override
    public List<CartInfo> getCartList() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList
                    .stream()
                    .sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime()))
                    .toList();
        }

        // 远程调用批量获取商品最新价格信息
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).toList();
            R<List<SkuPriceVo>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (skuPriceListResult.getCode() == R.FAIL) {
                throw new ServiceException("批量获取商品最新价格失败：" + skuPriceListResult.getMsg());
            }
            List<SkuPriceVo> skuPriceVoList = skuPriceListResult.getData();

            if (!CollectionUtils.isEmpty(skuPriceVoList)) {
                Map<Long, BigDecimal> collect = skuPriceVoList
                        .stream()
                        .collect(Collectors.toMap(SkuPriceVo::getSkuId, SkuPriceVo::getSalePrice));

                // 比较价格，若有变化则更新
                for (CartInfo cartInfo : cartInfoList) {
                    BigDecimal price = collect.get(cartInfo.getSkuId());
                    if (price != null && price.compareTo(cartInfo.getSkuPrice()) != 0) {
                        // cartInfo.setSkuPrice(price);
                        boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
                    }
                }
            }
        }

        return cartInfoList;
    }

    @Override
    public void deleteCart(Long skuId) {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        boundHashOperations.delete(skuId.toString());
    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        if (boundHashOperations.hasKey(skuId.toString())) {
            // 获取用户选择的商品
            CartInfo cartInfo = boundHashOperations.get(skuId.toString());
            // cartInfoUpd 写回缓存
            cartInfo.setIsChecked(isChecked);
            // 更新缓存
            boundHashOperations.put(skuId.toString(), cartInfo);
        }
    }

    @Override
    public void allCheckCart(Integer isChecked) {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            for (CartInfo cartInfo : cartInfoList) {
                cartInfo.setIsChecked(isChecked);
                boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
            }
        }
    }

    @Override
    public void clearCart() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        redisTemplate.delete(cartKey);
    }

    /**
     * 获取购物车中选中的商品列表
     */
    @Override
    public List<CartInfo> getCartCheckedList() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList = cartInfoList
                    .stream()
                    .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                    .toList();
        }

        return cartInfoList;
    }

    @Override
    public Boolean deleteCartCheckedList() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();

        if (!CollectionUtils.isEmpty(cartInfoList)) {
            cartInfoList
                    .stream()
                    .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                    .forEach(cartInfo -> boundHashOperations.delete(cartInfo.getSkuId().toString()));
        }

        return true;
    }

    @Override
    public Boolean updateCartPrice() {
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);
        BoundHashOperations<String, String, CartInfo> boundHashOperations = redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = boundHashOperations.values();

        if (!CollectionUtils.isEmpty(cartInfoList)) {
            /*
            // V1版
            for (CartInfo cartInfo : cartInfoList) {
                R<SkuPriceVo> skuPriceResult = remoteProductService.getSkuPrice(cartInfo.getSkuId(), SecurityConstants.INNER);
                if (skuPriceResult.getCode() == R.FAIL) {
                    throw new ServiceException("远程调用失败：" + skuPriceResult.getMsg());
                }
                // 实时价格
                SkuPriceVo skuPriceVo = skuPriceResult.getData();

                if (skuPriceVo.getSalePrice().compareTo(cartInfo.getSkuPrice()) != 0) {
                    // 更新 skuPrice
                    cartInfo.setSkuPrice(skuPriceVo.getSalePrice());
                    // 将更新后的 cartInfo写回 redis缓存
                    boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
                }
            }
            */
            // V2版，优化
            List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).toList();
            R<List<SkuPriceVo>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (skuPriceListResult.getCode() == R.FAIL) {
                throw new ServiceException("远程调用失败：" + skuPriceListResult.getMsg());
            }
            List<SkuPriceVo> skuPriceVoList = skuPriceListResult.getData();
            Map<Long, BigDecimal> skuPriceVoMap = skuPriceVoList.stream().collect(Collectors.toMap(SkuPriceVo::getSkuId, SkuPriceVo::getSalePrice));

            for (CartInfo cartInfo : cartInfoList) {
                BigDecimal price = skuPriceVoMap.get(cartInfo.getSkuId());
                if (price.compareTo(cartInfo.getSkuPrice()) != 0) {
                    // 更新 skuPrice
                    cartInfo.setSkuPrice(price);
                    // 将更新后的 cartInfo写回 redis缓存
                    boundHashOperations.put(cartInfo.getSkuId().toString(), cartInfo);
                }
            }
        }

        return true;
    }

    /**
     * 组装购物车 key
     */
    private String getCartKey(Long userId) {
        //定义key user:userId:cart
        return "user:cart:" + userId;
    }
}
